#ifndef UL_LINK_H_ 
#define UL_LINK_H_
#include <stddef.h>
#include <sys/types.h>
#include "ul_log_adapter.h"
namespace LinuxNetworkUtility
{
  /// @class  single link item
  class SLink
  {
  public:
    /// @fn constructor
    inline SLink()
    {
      initialize();
    }

    /// @fn destructor
    virtual ~SLink()
    {
      next_ = NULL;
    }

    /// @fn check if single list is empty
    inline bool is_empty() const
    {
      return NULL == next_;
    }

    /// @fn get next item in single list
    inline SLink * next()
    {
      return next_;
    }

    /// @fn extract the item after this
    inline SLink * extract_next()
    {
      SLink *result = next_;
      if (result != NULL)
      {
        next_ = result->next_;
      }
      return result;
    }
    
    inline void insert(SLink *it)
    {
      if(NULL != it)
      {
        next_ = it;
      }
    }
  private:
    /// @fn initialize
    inline void initialize()
    {
      next_ = NULL;
    }
    /// @property pointer to next obj in single list
    SLink * next_;
  };

  /// @class  double link list item
  class DLink
  {
  public:
    /// @fn constructor
    inline DLink()
    {
      initialize();
    }   
    /// @fn check if double list is empty
    inline bool is_empty() const
    {
      if (NULL == next_ || NULL == prev_ )
      {
        UL_LOG_ERROR("dlink item corrupt [link_addr:%p,next:%p,prev:%p]", this, next_, prev_);
        return true;
      }
      return(next_ == this);
    }

    /// @fn insert an item after this DLink
    inline void insert_next(DLink & link)
    {
      if (NULL == next_ || NULL == prev_  || NULL == link.next_ || NULL == link.prev_)
      {
        UL_LOG_ERROR("dlink item corrupt [this:%p,next:%p,prev:%p,insert_item:%p,next:%p,prev:%p]",
                     this, next_, prev_, &link, link.next_, link.prev_);
      }
      else
      {
        link.next_ = next_;
        link.prev_ = this;
        next_->prev_ = &link;
        next_ = &link;
      }
    }

    /// @fn insert an item before this DLink
    inline void insert_prev(DLink & link)
    {
      if (NULL == next_ || NULL == prev_  || NULL == link.next_ || NULL == link.prev_)
      {
        UL_LOG_ERROR("dlink item corrupt [this:%p,next:%p,prev:%p,insert_item:%p,next:%p,prev:%p]",
                     this, next_, prev_, &link, link.next_, link.prev_);
      }
      else
      {
        link.prev_ = prev_;
        link.next_ = this;
        prev_->next_ = &link;
        prev_ = &link;
      }
    }

    /// @fn remove self from double list
    inline void remove()
    {
      if (next_ == NULL || prev_ == NULL)
      {
        UL_LOG_ERROR("dlink item corrupt [this:%p,next:%p,prev:%p]", this, next_, prev_);
      }
      else
      {
        prev_->next_ = next_;
        next_->prev_ = prev_;
        initialize();
      }
    }

    /// @fn remove and return the item after self if exist
    inline DLink * extract_next()
    {
      DLink *result = NULL;
      if (!is_empty())
      {
        result = next_;
        result->remove();
      }
      return result;
    }

    /// @fn remove and return the item before self if exist
    inline DLink * extract_prev()
    {
      DLink *result = NULL;
      if (!is_empty())
      {
        result = prev_;
        result->remove();
      }
      return result;
    }

    /// @fn replace self with link
    inline void replace(DLink &link)
    {
      if (NULL == next_ || NULL == prev_  || NULL == link.next_ || NULL == link.prev_)
      {
        UL_LOG_ERROR("dlink item corrupt [this:%p,next:%p,prev:%p,insert_item:%p,next:%p,prev:%p]",
                     this, next_, prev_, &link, link.next_, link.prev_);
      }
      else
      {
        next_->prev_ = &link;
        prev_->next_ = &link;
        link.prev_ = prev_;
        link.next_ = next_;
        initialize();
      }
    }

    /// @fn get next item
    inline DLink *next()
    {
      return next_;
    }

    /// @fn get preivous item
    inline DLink *prev()
    {
      return prev_;
    }
  private:
    /// @fn initialize
    inline void initialize()
    {
      next_ = this;
      prev_ = this;
    }
    /// @property point to next item in double list
    DLink * next_;
    /// @property point to previous item in double list
    DLink * prev_;
  };
}
/// @def get the object of type "type" that contains the field 
/// "field" stating in address "address"
#ifndef CONTAINING_RECORD
  #define CONTAINING_RECORD(address, type, field) ((type *)( 				            \
                                                 (char*)(address) - 			      \
                                                 (long)(&((type *)1)->field) + 1))
#endif
#endif /* UL_LINK_H_ */
